﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Remoting.Messaging;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Encrypt.DES
{
    /// <summary>
    /// 数据DES 加密 及 解密 类
    /// 提供加密 及 解密方法
    /// </summary>
    public static class CMY_DES_Encrypt
    {
        /// <summary>
        /// 执行DES加密解密 ECB模式  无填充数据    
        /// </summary>
        /// <param name="Mes_IN_OUT">消息输入 结果输出  长度必须为8字节的整数倍</param>
        /// <param name="Keybuff">秘钥     8字节、16字节、24字节</param>
        /// <param name="Encryptmode">真为加密   假为 解密</param>
        /// <returns>返回0执行成功  其它错误信息</returns>
        public static int DES_ENC_DEC_ECB(byte[] Mes_IN_OUT, byte[] Keybuff, bool Encryptmode)
        {
            if (((Mes_IN_OUT.Length % 8) > 0) || (Mes_IN_OUT.Length == 0))
            {
                return 1;
            }
            if ((Keybuff.Length != 8) && (Keybuff.Length != 16) && (Keybuff.Length != 24))
            {
                return 2;
            }
            if (Keybuff.Length == 8)  //单DES
            {
                DESCryptoServiceProvider DEScrypto = new DESCryptoServiceProvider();
                DEScrypto.Mode = CipherMode.ECB;    //设置加密模式
                DEScrypto.Key = Keybuff;         //装载加密密钥
                DEScrypto.Padding = PaddingMode.None;   //不填充
                var DesEncrypt = Encryptmode ? DEScrypto.CreateEncryptor() : DEScrypto.CreateDecryptor();
                byte[] Buff = DesEncrypt.TransformFinalBlock(Mes_IN_OUT, 0, Mes_IN_OUT.Length);  //转换并保存结果
                DEScrypto.Clear(); //释放资源
                Array.Copy(Buff, Mes_IN_OUT, Mes_IN_OUT.Length);  //拷贝结果
            }
            else
            {
                //三DES  双倍长秘钥 及三倍长秘钥 ------------------
                TripleDESCryptoServiceProvider DEScrypto = new TripleDESCryptoServiceProvider();
                DEScrypto.Mode = CipherMode.ECB;    //设置加密模式
                DEScrypto.Key = Keybuff;         //装载加密密钥
                DEScrypto.Padding = PaddingMode.None;   //不填充
                var DesEncrypt = Encryptmode ? DEScrypto.CreateEncryptor() : DEScrypto.CreateDecryptor();
                byte[] Buff = DesEncrypt.TransformFinalBlock(Mes_IN_OUT, 0, Mes_IN_OUT.Length);  //转换并保存结果
                DEScrypto.Clear(); //释放资源
                Array.Copy(Buff, Mes_IN_OUT, Mes_IN_OUT.Length);  //拷贝结果
            }
            return 0;
        }

        /// <summary>
        /// DES加密解密 CBC模式 无填充数据  
        /// </summary>
        /// <param name="Mes_IN_OUT">消息输入 结果输出  长度必须为8字节的整数倍</param>
        /// <param name="Keybuff">秘钥     8字节、16字节、24字节</param>
        /// <param name="Encryptmode">真为加密   假为 解密</param>
        /// <returns>返回0执行成功  其它错误信息</returns>
        /// <returns></returns>
        public static int DES_ENC_DEC_CBC(byte[] IV_IN_OUT, byte[] Mes_IN_OUT, byte[] Keybuff, bool Encryptmode)
        {
            if (((Mes_IN_OUT.Length % 8) > 0) || (Mes_IN_OUT.Length == 0))
            {
                return 1;
            }
            if ((Keybuff.Length != 8) && (Keybuff.Length != 16) && (Keybuff.Length != 24))
            {
                return 2;
            }
            if (IV_IN_OUT.Length != 8)
            {
                return 3;
            }
            byte[] Buff;
            if (Keybuff.Length == 8)  //单DES
            {
                DESCryptoServiceProvider DEScrypto = new DESCryptoServiceProvider();
                DEScrypto.Mode = CipherMode.CBC;    //设置加密模式
                DEScrypto.IV = IV_IN_OUT;        //设置向量
                DEScrypto.Key = Keybuff;         //装载加密密钥
                DEScrypto.Padding = PaddingMode.None;   //不填充
                var DesEncrypt = Encryptmode ? DEScrypto.CreateEncryptor() : DEScrypto.CreateDecryptor();
                Buff = DesEncrypt.TransformFinalBlock(Mes_IN_OUT, 0, Mes_IN_OUT.Length);  //转换并保存结果
                DEScrypto.Clear(); //释放资源
            }
            else
            {
                //三DES  双倍长秘钥 及三倍长秘钥 ------------------
                TripleDESCryptoServiceProvider DEScrypto = new TripleDESCryptoServiceProvider();
                DEScrypto.Mode = CipherMode.CBC;    //设置加密模式
                DEScrypto.IV = IV_IN_OUT;        //设置向量
                DEScrypto.Key = Keybuff;         //装载加密密钥  秘钥大小会自动设置
                DEScrypto.Padding = PaddingMode.None;   //不填充
                var DesEncrypt = Encryptmode ? DEScrypto.CreateEncryptor() : DEScrypto.CreateDecryptor();
                Buff = DesEncrypt.TransformFinalBlock(Mes_IN_OUT, 0, Mes_IN_OUT.Length);  //转换并保存结果
                DEScrypto.Clear(); //释放资源
            }
            //拷贝下一个块的向量值
            //如果是加密操作  则下一个块的向量为上一个块的加密密文
            //如果是解密操作  则下一个块的向量为上一个块的原始密文
            Array.Copy(Encryptmode ? Buff : Mes_IN_OUT, (Encryptmode ? Buff.Length : Mes_IN_OUT.Length) - 8, IV_IN_OUT, 0, 8);
            Array.Copy(Buff, Mes_IN_OUT, Mes_IN_OUT.Length);  //拷贝结果
            return 0;
        }

        #region DES不检查弱密钥  CBC模式及ECB模式

        /// <summary>
        ///  DES加密解密 不检查弱秘钥（通过反射和反编译实现） CBC模式 无填充数据   
        /// </summary>
        /// <param name="IV_IN_OUT">初始化向量输入  下一个块向量输出</param>
        /// <param name="Mes_IN_OUT">消息输入 结果输出  长度必须为8字节的整数倍</param>
        /// <param name="Keybuff">秘钥     8字节、16字节、24字节</param>
        /// <param name="Encryptmode">真为加密   假为 解密</param>
        /// <returns>返回0执行成功  其它错误信息</returns>
        public static int DES_NoKey_ENC_DEC_CBC(byte[] IV_IN_OUT, byte[] Mes_IN_OUT, byte[] Keybuff, bool Encryptmode)
        {
            if (((Mes_IN_OUT.Length % 8) > 0) || (Mes_IN_OUT.Length == 0))
            {
                return 1;
            }
            if ((Keybuff.Length != 8) && (Keybuff.Length != 16) && (Keybuff.Length != 24))
            {
                return 2;
            }
            if (IV_IN_OUT.Length != 8)
            {
                return 3;
            }
            byte[] Buff;
            if (Keybuff.Length == 8)  //单DES
            {
                DESCryptoServiceProvider DEScrypto = new DESCryptoServiceProvider();
                DEScrypto.Padding = PaddingMode.None;   //不填充
                //这个采用反射 调用内部方法跳过弱密钥检查   结构、方法及变量名称通过反编译得到
                Type t = Type.GetType("System.Security.Cryptography.CryptoAPITransformMode");  //得到CryptoAPITransformMode结构
                //得到CryptoAPITransformMode结构中的一个值   此结构为一个枚举类型
                object obj = t.GetField(Encryptmode ? "Encrypt" : "Decrypt", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly).GetValue(t);
                //得到内部私有方法   加密算法中 初始化后最终调用此方法
                MethodInfo mi = DEScrypto.GetType().GetMethod("_NewEncryptor", BindingFlags.Instance | BindingFlags.NonPublic);
                //调用mi方法 其为内部_NewEncryptor 方法  填充秘钥、模式、向量、块大小、加密还是解密
                ICryptoTransform desCrypt = (ICryptoTransform)mi.Invoke(DEScrypto, new object[] { Keybuff, CipherMode.CBC, IV_IN_OUT, 0, obj });
                Buff = desCrypt.TransformFinalBlock(Mes_IN_OUT, 0, Mes_IN_OUT.Length);  //转换并保存结果
                DEScrypto.Clear(); //释放资源
            }
            else
            {
                //三DES  双倍长秘钥 及三倍长秘钥 ------------------
                TripleDESCryptoServiceProvider DEScrypto = new TripleDESCryptoServiceProvider();
                DEScrypto.Padding = PaddingMode.None;   //不填充
                DEScrypto.KeySize = Keybuff.Length * 8;  //设置秘钥长度 此设置已无效 只是用于方便调试
                //这个采用反射 调用内部方法跳过弱密钥检查
                Type t = Type.GetType("System.Security.Cryptography.CryptoAPITransformMode");  //得到CryptoAPITransformMode结构
                //得到CryptoAPITransformMode结构中的一个值   此结构为一个枚举类型
                object obj = t.GetField(Encryptmode ? "Encrypt" : "Decrypt", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly).GetValue(t);
                //得到内部私有方法 _NewEncryptor  加密算法中 初始化后最终调用此方法
                MethodInfo mi = DEScrypto.GetType().GetMethod("_NewEncryptor", BindingFlags.Instance | BindingFlags.NonPublic);
                //调用mi方法 其为内部_NewEncryptor 方法  填充秘钥、模式、向量、块大小、加密还是解密
                ICryptoTransform desCrypt = (ICryptoTransform)mi.Invoke(DEScrypto, new object[] { Keybuff, CipherMode.CBC, IV_IN_OUT, 0, obj });
                Buff = desCrypt.TransformFinalBlock(Mes_IN_OUT, 0, Mes_IN_OUT.Length);  //转换并保存结果
                DEScrypto.Clear(); //释放资源
            }
            //拷贝下一个块的向量值
            //如果是加密操作  则下一个块的向量为上一个块的加密密文
            //如果是解密操作  则下一个块的向量为上一个块的原始密文
            Array.Copy(Encryptmode ? Buff : Mes_IN_OUT, (Encryptmode ? Buff.Length : Mes_IN_OUT.Length) - 8, IV_IN_OUT, 0, 8);
            Array.Copy(Buff, Mes_IN_OUT, Mes_IN_OUT.Length);  //拷贝结果
            return 0;
        }

        /// <summary>
        /// DES加密解密 不检查弱秘钥（通过反射和反编译实现） ECB模式 无填充数据   
        /// </summary>
        /// <param name="Mes_IN_OUT">消息输入 结果输出  长度必须为8字节的整数倍</param>
        /// <param name="Keybuff">秘钥     8字节、16字节、24字节</param>
        /// <param name="Encryptmode">真为加密   假为 解密</param>
        /// <returns>返回0执行成功  其它错误信息</returns>
        /// <returns></returns>
        public static int DES_NoKey_ENC_DEC_ECB(byte[] Mes_IN_OUT, byte[] Keybuff, bool Encryptmode)
        {
            if (((Mes_IN_OUT.Length % 8) > 0) || (Mes_IN_OUT.Length == 0))
            {
                return 1;
            }
            if ((Keybuff.Length != 8) && (Keybuff.Length != 16) && (Keybuff.Length != 24))
            {
                return 2;
            }
            byte[] Buff;
            if (Keybuff.Length == 8)  //单DES
            {
                DESCryptoServiceProvider DEScrypto = new DESCryptoServiceProvider();
                DEScrypto.Padding = PaddingMode.None;   //不填充
                //这个采用反射 调用内部方法跳过弱密钥检查
                Type t = Type.GetType("System.Security.Cryptography.CryptoAPITransformMode");  //得到CryptoAPITransformMode结构
                //得到CryptoAPITransformMode结构中的一个值   此结构为一个枚举类型
                object obj = t.GetField(Encryptmode ? "Encrypt" : "Decrypt", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly).GetValue(t);
                //得到内部私有方法   加密算法中 初始化后最终调用此方法
                MethodInfo mi = DEScrypto.GetType().GetMethod("_NewEncryptor", BindingFlags.Instance | BindingFlags.NonPublic);
                //调用mi方法 其为内部_NewEncryptor 方法  填充秘钥、模式、向量、块大小、加密还是解密
                ICryptoTransform desCrypt = (ICryptoTransform)mi.Invoke(DEScrypto, new object[] { Keybuff, CipherMode.ECB, null, 0, obj });
                Buff = desCrypt.TransformFinalBlock(Mes_IN_OUT, 0, Mes_IN_OUT.Length);  //转换并保存结果
                DEScrypto.Clear(); //释放资源
            }
            else
            {
                //三DES  双倍长秘钥 及三倍长秘钥 ------------------
                TripleDESCryptoServiceProvider DEScrypto = new TripleDESCryptoServiceProvider();
                DEScrypto.Padding = PaddingMode.None;   //不填充
                DEScrypto.KeySize = Keybuff.Length * 8;  //设置秘钥长度 此设置已无效 只是用于方便调试
                //这个采用反射 调用内部方法跳过弱密钥检查
                Type t = Type.GetType("System.Security.Cryptography.CryptoAPITransformMode");  //得到CryptoAPITransformMode结构
                //得到CryptoAPITransformMode结构中的一个值   此结构为一个枚举类型
                object obj = t.GetField(Encryptmode ? "Encrypt" : "Decrypt", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly).GetValue(t);
                //得到内部私有方法 _NewEncryptor  加密算法中 初始化后最终调用此方法
                MethodInfo mi = DEScrypto.GetType().GetMethod("_NewEncryptor", BindingFlags.Instance | BindingFlags.NonPublic);
                //调用mi方法 其为内部_NewEncryptor 方法  填充秘钥、模式、向量、块大小、加密还是解密
                ICryptoTransform desCrypt = (ICryptoTransform)mi.Invoke(DEScrypto, new object[] { Keybuff, CipherMode.ECB, null, 0, obj });
                Buff = desCrypt.TransformFinalBlock(Mes_IN_OUT, 0, Mes_IN_OUT.Length);  //转换并保存结果
                DEScrypto.Clear(); //释放资源
            }
            Array.Copy(Buff, Mes_IN_OUT, Mes_IN_OUT.Length);  //拷贝结果
            return 0;
        }

        #endregion
    }
}
